#pragma once

#include <atomic>

namespace hawking {
namespace indexlib {

class SpinLock {
public:
    void lock() {
        while (flag.test_and_set(std::memory_order_acquire));
    }
    void unlock() { flag.clear(std::memory_order_release); }

private:
    std::atomic_flag flag = ATOMIC_FLAG_INIT;
};

class ScopedSpinLock {
public:
    ScopedSpinLock(SpinLock& lock) : lock_(lock) { lock_.lock(); }
    ~ScopedSpinLock() { lock_.unlock(); }

private:
    ScopedSpinLock(const ScopedSpinLock &) = delete;
    ScopedSpinLock &operator=(const ScopedSpinLock &) = delete;

private:
    SpinLock& lock_;
};

class ScopedSharedLock {
public:
    ScopedSharedLock(std::shared_mutex& mutex, bool need_lock) {
        if (need_lock) {
            lock_.reset(new std::shared_lock<std::shared_mutex>(mutex));
        }
    }
    ~ScopedSharedLock() {
        Unlock();
    }

    void Unlock() {
        if (lock_) {
            lock_->unlock();
            lock_.reset(nullptr);
        }
    }

private:
    std::unique_ptr<std::shared_lock<std::shared_mutex>> lock_;
};

}
}